﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using FALibrary.Sequence;
using FALibrary.DisplayObserver;
using FALibrary.Driver;

namespace FALibrary.Part
{
    public delegate bool FAInterlock(ref string msg);

    public class FAPartAction : FAObject
    {
        private Dictionary<string, dynamic> _parameters = new Dictionary<string, dynamic>();
        private List<FAInterlock> _interlockList = new List<FAInterlock>();
        private FASequence _sequence = null;
        private FAPart _part = null;

        public string ActionName { get; set; }
        public long Timeout { get; set; }
        public FAPart Part
        {
            get { return _part; }
            set { _part = value; }
        }

        public Dictionary<string, dynamic> Parameters
        {
            get { return _parameters; }
        }

        public List<FAInterlock> InterlockList
        {
            get { return _interlockList; }
        }

        public FASequence Sequence
        {
            get { return _sequence; }            
        }

        public void Execute(object sender)
        {
            if (IsInterlock() == true)
                return;

            Part.DoAction(ActionName, _parameters);
        }

        public void CreateSequence()
        {
            Object thisLock = new Object();
            lock (thisLock)
            {
                if (_sequence == null)
                {
                    _sequence = new FASequence();
                    _sequence.Name = ActionName + " Sequence";
                    _sequence.AddWatcher(IsTimeout);
                }
            }
        }

        public bool IsInterlock()
        {
            string msg = "";

            foreach (FAInterlock item in _interlockList)
            {
                bool result;
                try
                {
                    result = item(ref msg);
                }
                catch (Exception e)
                {
                    result = true;
                    msg = e.Message;
                }

                if (result == true)
                {
                    msg = "DO NOT " + ActionName + " " + msg;
                    return true;
                }                
            }

            return false;
        }

        private void IsTimeout(FASequence actor, long time)
        {
            if (time > Timeout)
            {
                actor.SetAlarm();
            }
        }
    }

    public class FAPartDisplayControlInfo
    {
        public Control Control { get; set; }
        public FADisplayObserver DisplayObserver { get; set; }

        public FAPartDisplayControlInfo() { }
        public FAPartDisplayControlInfo(Control control, FADisplayObserver observer)
        {
        }
    }

    public abstract class FAPart : FAObject
    {        
        private Dictionary<string, FAPartAction> _actions = new Dictionary<string, FAPartAction>();
        private Dictionary<string, List<FAPartDisplayControlInfo>> _displayControls = new Dictionary<string, List<FAPartDisplayControlInfo>>();

        protected Dictionary<string, FAPartAction> Actions
        {
            get { return _actions; }
        }

        protected Dictionary<string, List<FAPartDisplayControlInfo>> DisplayControls
        {
            get { return _displayControls; }
        }              

        public FADriver Driver
        {
            get;
            set;
        }
        public string Description
        {
            get;
            set;
        }

        public void DoAction(string actionName, Dictionary<string, dynamic> parameters)
        {
        }

        public abstract void LoadParameters(XElement parameters);

        public void AddAction(string command)
        {
            FAPartAction action = new FAPartAction();
            action.ActionName = command;
            action.Part = this;

            if (Actions.ContainsKey(command) == false)
                Actions.Add(command, action);
            else
                Actions[command] = action;
        }

        public void AddAliasAction(string alias, string command)
        {
            FAPartAction action = new FAPartAction();
            action.ActionName = command;
            action.Part = this;

            if (Actions.ContainsKey(alias) == false)
                Actions.Add(alias, action);
            else
                Actions[alias] = action;
        }

        public void AddDisplayControl(string key, Control control, FADisplayObserver observer)
        {
            if (DisplayControls.ContainsKey(key))
            {
                DisplayControls[key].Add(new FAPartDisplayControlInfo(control, observer));
            }
            else
            {
                DisplayControls.Add(key, new List<FAPartDisplayControlInfo>());
            }            
        }

        public void DoDisplay()
        {
            foreach (KeyValuePair<string, List<FAPartDisplayControlInfo>> item in DisplayControls)
            {
                foreach (FAPartDisplayControlInfo aControlInfo in item.Value)
                {
                    aControlInfo.DisplayObserver.Nofity();                    
                }
            }
        }
    }
}
